package club.kingyin.kyblogprofile.core.es;

import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Locale;
import java.util.Random;
import java.util.Set;

@Service("ikService")
public class IkMinioServe implements IkService{

    @Resource
    private MinioClient minioClient;

    private static final String WORDS_NAME = "/ik/word.txt";
    private static final String STOPS_NAME = "/ik/stop.txt";
    private static final String CLOUD = "cloud";
    private static final String TEXT = "text/plain";

    private Set<String> words = new HashSet<>();
    private Set<String> stops = new HashSet<>();
    private Set<String> cache = new HashSet<>();

    // 拉取远程数据
    private void getMinioData() {
        getTxtToSetFromMinio(words,WORDS_NAME);
        getTxtToSetFromMinio(stops,STOPS_NAME);
    }

    private void getMinioWord() {
        getTxtToSetFromMinio(words,WORDS_NAME);
    }

    private void getMinioStop() {
        getTxtToSetFromMinio(stops,STOPS_NAME);
    }

    // 推送远程数据
    private boolean pushMinioData(String name) {
        try {
            switch (name) {
                case WORD:
                    ByteArrayInputStream ws = new ByteArrayInputStream(wordsToString(words).getBytes(StandardCharsets.UTF_8));
                    minioClient.putObject(PutObjectArgs.builder().bucket(CLOUD).object(WORDS_NAME).contentType(TEXT).stream(ws, ws.available(), -1).build());
                    return true;
                case STOP:
                    ByteArrayInputStream ss = new ByteArrayInputStream(wordsToString(stops).getBytes(StandardCharsets.UTF_8));
                    minioClient.putObject(PutObjectArgs.builder().bucket(CLOUD).object(STOPS_NAME).contentType(TEXT).stream(ss, ss.available(), -1).build());
            }
                return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    private boolean pushWord() {
        return pushMinioData(WORD);
    }

    private boolean pushStop() {
        return pushMinioData(STOP);
    }

    private boolean getTxtToSetFromMinio(Set<String> set, String name) {
        try {
            InputStream cloud = minioClient.getObject(GetObjectArgs.builder().bucket(CLOUD).object(name).build());
            BufferedReader br = new BufferedReader(new InputStreamReader(cloud));
            String str;
            while ((str = br.readLine()) != null) {
                set.add(str);
                cache.add(str.toUpperCase());
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static String wordsToString(Set<String> words) {
        StringBuffer sb = new StringBuffer();
        for (String word : words) {
            sb.append(word).append("\r\n");
        }
        return sb.toString();
    }



    @Override
    public boolean hasWord(String word) {
        getMinioWord();
        return this.cache.contains(word.toUpperCase());
    }

    @Override
    public boolean hasStop(String stop) {
        getMinioStop();
        return this.stops.contains(stop);
    }

    @Override
    public int addWord(String... words) {
        getMinioWord();
        int count = 0;
        for (String word : words) {
            if (!hasWord(word)) {
                ++count;
                this.words.add(word);
            }
        }
        return count==0?0:pushWord()?count:-1;
    }

    @Override
    public int addStop(String... stops) {
        getMinioStop();
        int count = 0;
        for (String stop : stops) {
            if (!hasStop(stop)) {
                ++count;
                this.stops.add(stop);
            }
        }
        return count==0?0:pushStop()?count:-1;
    }

    @Override
    public int removeWord(String... words) {
        getMinioWord();
        int count = 0;
        for (String word : words) {
            if (hasWord(word)) {
                ++count;
                this.words.remove(word);
            }
        }

        return count==0?0:pushWord()?count:-1;
    }

    @Override
    public int removeStop(String... stops) {
        getMinioStop();
        int count = 0;
        for (String stop : stops) {
            if (hasStop(stop)) {
                ++count;
                this.stops.remove(stop);
            }
        }
        return count==0?0:pushStop()?count:-1;
    }

    @Override
    public Set<String> getWords() {
        getMinioWord();
        return words;
    }

    public Set<String> random(int size) {
        getWords();
        Object[] ws =  words.toArray();
        if (size>=words.size()-1) {
            return words;
        } else {
            Random random = new Random();
            Set<String> res = new HashSet<>();
            while (res.size()<size) {
                res.add((String) ws[random.nextInt(words.size())]);
            }
            return res;
        }
    }

    @Override
    public Set<String> getStops() {
        getMinioStop();
        return stops;
    }
}
